package TcpServer

import (
	"errors"
	"fmt"
	"gitee.com/fierce_wolf/go-fox-edge-common/commLogger"
	"gitee.com/fierce_wolf/go-fox-edge-common/commUtil/Byte"
	"net"
	"strconv"
)

type TcpServer struct {
	Handler IHandler
	Notify  INotify
	Port    int
}

func (e *TcpServer) StartTcpServer() error {
	// 监听端口
	port := strconv.Itoa(e.Port)
	listener, err := net.Listen("tcp", ":"+port)
	if err != nil {
		commLogger.Error("链接异常:" + err.Error())
		return err
	}
	defer listener.Close()

	commLogger.Info("启动TCP SERVER : 127.0.0.1:" + port)

	for {
		conn, err := listener.Accept()
		if err != nil {
			commLogger.Error("Accept连接错误:" + err.Error())
			continue
		}

		go e.process(conn)
	}
}

func (e *TcpServer) process(conn net.Conn) {
	defer func() {
		e.Notify.ChannelClose(conn)
		conn.Close()
	}()

	e.Notify.ChannelActive(conn)

	buffer := &Byte.Buffer{}
	buffer.Reset()

	// 创建一个传递消息的chan
	exit := make(chan int, 1)
	read := make(chan int, 1)

	go e.reader(conn, buffer, read, exit)

	for true {
		select {
		case <-exit:
			return
		case <-read:
			err := e.onReceive(conn, buffer)
			if err != nil {
				e.Notify.ExceptionCaught(conn, err)
				return
			}
		}
	}
}

func (e *TcpServer) onReceive(conn net.Conn, buffer *Byte.Buffer) (err error) {
	// 定义一个最终的异常拦截，用来防止可能的代码BUG
	defer func() {
		if r := recover(); r != nil {
			err = errors.New(fmt.Sprintf("处理异常：远端设备->"+conn.RemoteAddr().String()+" ->%v", r))
		}
	}()

	// 获得最小包长度
	headerLength, err := e.Handler.GetHeaderLength()
	if err != nil {
		return err
	}

	// 检查：长度是否达到最小长度要求
	cnt := buffer.ReadableBytes()
	if cnt < headerLength {
		return nil
	}

	// 检查：包头是否是合法格式
	packLen, ok := buffer.TryRead(func(data []byte) (int, bool) {
		// 根据包头，简单验证数据的合法性
		invalid, err := e.Handler.InvalidHeader(data[:headerLength])
		if err != nil || invalid == true {
			return 0, false
		}

		// 从合法的包头中，取出包长度
		packLen, err := e.Handler.GetPackLength(data[:headerLength])
		if err != nil {
			return 0, false
		}

		return packLen, true
	})
	if !ok {
		return errors.New("非法的包头")
	}

	// 检查：报文是否接收完成
	cnt = buffer.ReadableBytes()
	if cnt < packLen {
		return nil
	}

	// 取出数据
	data, err := buffer.ReadBytes(packLen)
	if err != nil {
		return errors.New("本地接收缓存异常")
	}

	// 上报数据
	e.Notify.ChannelRead(conn, data)

	return nil
}

func (e *TcpServer) reader(conn net.Conn, buffer *Byte.Buffer, read chan int, exit chan int) {
	buff := make([]byte, 4096)

	for {
		// 等待数据的到达：这是一个阻塞的操作，直到数据的到达
		cnt, err := conn.Read(buff)
		if err != nil {
			exit <- 1
			break
		}

		// 写入数据
		err = buffer.WriteBytes(buff[0:cnt])
		if err != nil {
			buffer.Reset()
		}

		read <- 1
	}

	//关闭ch
	close(exit)
}
